package com.example.library.controller;

import com.auth0.jwt.interfaces.Claim;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.library.common.Result;
import com.example.library.entity.User;
import com.example.library.service.IUserService;
import com.example.library.utils.JwtUtil;
import com.example.library.utils.Md5Util;
import com.example.library.utils.TokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.example.library.dto.ChangePasswordRequest;

import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 用户管理
 *
 * 该控制器处理用户注册、登录、登出、Token 验证以及删除用户等操作。
 */
@RestController
@CrossOrigin
@RequestMapping("/user")
@Validated
public class UserController {

    @Autowired
    private IUserService userService;  // 注入用户服务类

    @Autowired
    private RedisTemplate<String, String> redisTemplate;  // 注入 Redis 模板，用于 Token 缓存

    @Autowired
    private TokenUtil tokenUtil;  // 注入 Token 工具类

    /**
     * 用户注册
     *
     * 该方法用于注册新用户，用户名和邮箱必须唯一，密码加密后存储。
     *
     * @param user 要注册的用户对象
     * @return 注册结果的 Result 对象
     */
    @PostMapping("/register")
    public Result register(@RequestBody User user) {
        // 检查用户名是否已存在
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName, user.getUserName());
        User u = userService.getOne(queryWrapper);

        if (u != null) {
            return Result.error("用户名已被注册");
        }

        // 检查邮箱是否已存在
        LambdaQueryWrapper<User> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.eq(User::getUserEmail, user.getUserEmail());
        User email = userService.getOne(queryWrapper2);

        if (email != null) {
            return Result.error("邮箱已被注册");
        }

        // 密码加密处理
        String hashedPassword = Md5Util.getMD5String(user.getUserPassword());
        user.setUserPassword(hashedPassword);  // 设置加密后的密码
        user.setUserRole("user");  // 默认角色为普通用户
        user.setUserStatus("0");   // 默认状态为 "正常"

        // 保存用户到数据库
        userService.save(user);
        return Result.success("注册成功");
    }

    /**
     * 用户登录
     *
     * 该方法验证用户名和密码，生成 JWT Token，并返回用户信息和 Token。
     *
     * @param user 包含用户名和密码的用户对象
     * @return 登录成功后的 Token 和用户信息
     */
    @PostMapping("/login")
    public Result<Map<String, Object>> login(@RequestBody User user) {
        // 验证用户名和密码
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName, user.getUserName())
                .eq(User::getUserPassword, Md5Util.getMD5String(user.getUserPassword()));

        User one = userService.getOne(queryWrapper);

        if (one == null) {
            return Result.error(404, "用户名或者密码错误");
        }

        // 检查用户状态是否为 "0"（正常）
        if (!"0".equals(one.getUserStatus())) {
            return Result.error(403, "该账号已被禁用或无效");
        }

        // 生成 JWT Token
        HashMap<String, Object> claims = new HashMap<>();
        claims.put("userId", one.getUserId());  // 存储 userId
        claims.put("userName", one.getUserName());  // 存储 userName
        claims.put("userRole", one.getUserRole()); // 存储 userRole
        String token = JwtUtil.genToken(claims);

        // 将 Token 存储到 Redis 中，设置过期时间为 1 小时
        redisTemplate.opsForValue().set("token:" + one.getUserName(), token, 3600, TimeUnit.SECONDS);

        // 构造返回数据
        Map<String, Object> responseData = new HashMap<>();
        responseData.put("token", token);
        responseData.put("user", one);
        return Result.success(responseData);
    }

    /**
     * 用户登出
     *
     * 该方法通过删除 Redis 中的 Token 来实现用户登出。
     *
     * @param token 请求头中的授权 Token
     * @return 登出结果
     */
    @PostMapping("/logout")
    public Result logout(@RequestHeader("Authorization") String token) {
        try {
            // 解析 Token 获取 claims
            Map<String, Claim> claims = JwtUtil.parseToken(token);
            String userId = claims.get("userName").asString();

            // 删除 Redis 中的 Token
            Boolean deleted = redisTemplate.delete("token:" + userId);
            if (Boolean.TRUE.equals(deleted)) {
                return Result.success("登出成功");
            } else {
                return Result.error("登出失败，Token 未找到");
            }
        } catch (Exception e) {
            return Result.error(401, "无效的 Token");
        }
    }

    /**
     * Token 验证
     *
     * 该方法用于验证传入的 Token 是否有效。
     *
     * @param authorizationHeader 请求头中的授权 Token
     * @return Token 验证结果
     */
    @PostMapping("/verifyToken")
    public Result verifyToken(@RequestHeader("Authorization") String authorizationHeader) {
        return tokenUtil.validateToken(authorizationHeader);
    }

    /**
     * 获取当前用户的信息
     *
     * 该方法从 Token 中获取用户名，并查询该用户的所有信息。
     *
     * @param authorizationHeader 请求头中的授权信息，包含 JWT Token
     * @return 包含该用户信息的 Result 对象
     */
    @GetMapping("/info")
    public Result<User> getUserInfo(@RequestHeader("Authorization") String authorizationHeader) {
        // 从请求头中提取 Token，移除 "Bearer " 前缀
        String token = authorizationHeader.startsWith("Bearer ") ? authorizationHeader.substring(7) : authorizationHeader;

        // 验证 Token 是否有效
        Result<String> tokenResult = tokenUtil.validateToken(token);
        if (!tokenResult.isSuccess()) {
            return Result.error(401, "无效的 Token");
        }

        // 从 Token 中获取用户名
        String username = tokenUtil.getClaimFromToken(token, "userName");
        if (username == null) {
            return Result.error(401, "无效的 Token，无法获取用户名");
        }

        // 查询指定用户名的用户信息
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName, username);
        User user = userService.getOne(queryWrapper);

        if (user == null) {
            return Result.error(404, "用户不存在");
        }

        return Result.success(user);
    }

    /**
     * 修改用户状态
     *
     * 该方法允许管理员通过用户名修改用户的状态，如禁用或启用账号。
     *
     * @param username 要修改状态的用户名
     * @param status 要设置的新状态，0 表示正常，1 表示禁用
     * @param authorizationHeader 请求头中的授权信息，包含 JWT Token
     * @return 修改状态结果
     */
    @PatchMapping("/updateStatus/{username}")
    public Result updateUserStatus(@PathVariable("username") String username, @RequestParam("status") String status,
                                   @RequestHeader("Authorization") String authorizationHeader) {
        // 从 Token 中提取 Token，移除 "Bearer " 前缀
        String token = authorizationHeader.startsWith("Bearer ") ? authorizationHeader.substring(7) : authorizationHeader;

        // 验证 Token 是否有效
        Result<String> tokenResult = tokenUtil.validateToken(token);
        if (!tokenResult.isSuccess()) {
            return Result.error(401, "无效的 Token");
        }

        // 从 Token 中获取用户角色
        String userRole = tokenUtil.getClaimFromToken(token, "userRole");
        if (userRole == null || !"admin".equals(userRole)) {
            return Result.error(403, "无权限操作，只有管理员可以修改用户状态");
        }

        // 根据用户名查询用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName, username);
        User user = userService.getOne(queryWrapper);

        if (user == null) {
            return Result.error(404, "用户不存在");
        }

        // 更新用户状态
        user.setUserStatus(status);
        boolean updated = userService.updateById(user);
        if (updated) {
            return Result.success("用户状态更新成功");
        } else {
            return Result.error("更新用户状态失败");
        }
    }

    /**
     * 获取所有普通用户的信息
     *
     * 该方法允许管理员获取所有普通用户（user）的信息。
     *
     * @param authorizationHeader 请求头中的授权信息，包含 JWT Token
     * @return 包含所有普通用户信息的 Result 对象
     */
    @GetMapping("/users")
    public Result<List<User>> getAllNormalUsers(@RequestHeader("Authorization") String authorizationHeader) {
        // 从请求头中提取 Token，移除 "Bearer " 前缀
        String token = authorizationHeader.startsWith("Bearer ") ? authorizationHeader.substring(7) : authorizationHeader;

        // 验证 Token 是否有效
        Result<String> tokenResult = tokenUtil.validateToken(token);
        if (!tokenResult.isSuccess()) {
            return Result.error(401, "无效的 Token");
        }

        // 从 Token 中获取用户角色
        String userRole = tokenUtil.getClaimFromToken(token, "userRole");
        if (userRole == null || !"admin".equals(userRole)) {
            return Result.error(403, "无权限操作，只有管理员可以获取所有普通用户信息");
        }

        // 查询所有普通用户（userRole == "user"）
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserRole, "user");
        List<User> users = userService.list(queryWrapper);

        // 返回用户列表
        return Result.success(users);
    }

    /**
     * 修改用户密码
     *
     * 该方法允许已认证的用户修改自己的密码。
     *
     * @param changePasswordRequest 包含旧密码和新密码的请求对象
     * @param authorizationHeader 请求头中的授权 Token
     * @return 修改结果的 Result 对象
     */
    @PostMapping("/changePassword")
    public Result<String> changePassword(@RequestBody @Validated ChangePasswordRequest changePasswordRequest,
                                         @RequestHeader("Authorization") String authorizationHeader) {
        try {
            // 从 Token 中提取 Token，移除 "Bearer " 前缀
            String token = authorizationHeader.startsWith("Bearer ") ? authorizationHeader.substring(7) : authorizationHeader;

            // 验证 Token 是否有效
            Result<String> tokenResult = tokenUtil.validateToken(token);
            if (!tokenResult.isSuccess()) {
                return Result.error(401, "无效的 Token");
            }

            // 从 Token 中获取用户名
            String username = tokenUtil.getClaimFromToken(token, "userName");
            if (username == null) {
                return Result.error(401, "无效的 Token，无法获取用户名");
            }

            // 根据用户名查询用户
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getUserName, username);
            User user = userService.getOne(queryWrapper);

            if (user == null) {
                return Result.error(404, "用户不存在");
            }

            // 验证旧密码是否正确
            String hashedOldPassword = Md5Util.getMD5String(changePasswordRequest.getOldPassword());
            if (!hashedOldPassword.equals(user.getUserPassword())) {
                return Result.error(400, "旧密码不正确");
            }

            // 加密新密码并更新用户信息
            String hashedNewPassword = Md5Util.getMD5String(changePasswordRequest.getNewPassword());
            user.setUserPassword(hashedNewPassword);
            boolean updated = userService.updateById(user);

            if (updated) {
                // 更新 Redis 中的 Token（可选，根据具体需求）
                HashMap<String, Object> claims = new HashMap<>();
                claims.put("userId", user.getUserId());
                claims.put("userName", user.getUserName());
                claims.put("userRole", user.getUserRole());
                String newToken = JwtUtil.genToken(claims);
                redisTemplate.opsForValue().set("token:" + user.getUserName(), newToken, 3600, TimeUnit.SECONDS);

                return Result.success("密码修改成功");
            } else {
                return Result.error(500, "密码修改失败，请重试");
            }

        } catch (Exception e) {
            return Result.error(500, "服务器内部错误");
        }
    }

    /**
     * 删除用户
     *
     * 该方法允许管理员通过用户 ID 删除用户，并从 Redis 中删除该用户的 Token。
     *
     * @param id 要删除的用户的 ID
     * @param authorizationHeader 请求头中的授权信息，包含 JWT Token
     * @return 删除结果的 Result 对象
     */
    @DeleteMapping("/delete/{id}")
    public Result deleteUser(@PathVariable("id") Integer id, @RequestHeader("Authorization") String authorizationHeader) {
        // 从请求头中提取 Token，移除 "Bearer " 前缀
        String token = authorizationHeader.startsWith("Bearer ") ? authorizationHeader.substring(7) : authorizationHeader;

        // 验证 Token 是否有效
        Result<String> tokenResult = tokenUtil.validateToken(token);
        if (!tokenResult.isSuccess()) {
            return Result.error(401, "无效的 Token");
        }

        // 从 Token 中获取用户角色
        String userRole = tokenUtil.getClaimFromToken(token, "userRole");
        if (userRole == null || !"admin".equals(userRole)) {
            return Result.error(403, "无权限操作，只有管理员可以删除用户");
        }

        // 删除数据库中的指定用户
        boolean isDeleted = userService.removeById(id);

        if (isDeleted) {
            // 如果用户删除成功，删除 Redis 中对应的 Token
            redisTemplate.delete("token:" + id);
            return Result.success("用户删除成功");
        } else {
            return Result.error("删除用户失败");
        }
    }
    /**
     * 获取在线用户数量
     *
     * 该方法统计 Redis 中以 "token:" 开头的键的数量，以返回当前在线用户的数量。
     *
     * @return 包含在线用户数量的 Result 对象
     */
    @GetMapping("/onlineUsers")
    public Result<Integer> getOnlineUsers() {
        try {
            // 定义 Redis 中 Token 的键前缀
            String tokenKeyPattern = "token:*";

            // 使用 RedisTemplate 获取所有匹配的键
            Set<String> keys = redisTemplate.keys(tokenKeyPattern);

            // 计算在线用户数量（即匹配的键的数量）
            int onlineUserCount = keys != null ? keys.size() : 0;

            // 返回在线用户数量
            return Result.success(onlineUserCount);
        } catch (Exception e) {
            // 处理可能的异常，例如 Redis 连接失败
            return Result.error(500, "无法获取在线用户数量");
        }
    }

}
